package com.oa.activiti.controller;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipInputStream;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;

import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.Model;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.apache.commons.io.FilenameUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.oa.activiti.dto.DefinitionDto;
import com.oa.entity.ExtPageable;
import com.oa.entity.ExtjsAjaxResult;

@Controller
@RequestMapping("/definition")
public class DefinitionController {
	@Resource
	private RepositoryService repositoryService;

	@RequestMapping(value = "/list")
	public @ResponseBody Page<DefinitionDto> processAjaxList(ExtPageable pageable) {
		List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery().list();
		List<DefinitionDto> dtoLists = null;

		if (processDefinitionList != null) {
			dtoLists = new ArrayList<>();
			for (ProcessDefinition pd : processDefinitionList) {
				DefinitionDto dtoTemp = new DefinitionDto();

				dtoTemp.setId(pd.getId());
				dtoTemp.setCategory(pd.getCategory());
				dtoTemp.setName(pd.getName());
				dtoTemp.setKey(pd.getKey());
				dtoTemp.setDescription(pd.getDescription());
				dtoTemp.setVersion(pd.getVersion());
				dtoTemp.setResourceName(pd.getResourceName());
				dtoTemp.setDeploymentId(pd.getDeploymentId());
				Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(pd.getDeploymentId())
						.singleResult();
				if (deployment != null) {
					dtoTemp.setDeploymentTime(deployment.getDeploymentTime());
				}

				dtoTemp.setDiagramResourceName(pd.getDiagramResourceName());
				dtoTemp.setTenantId(pd.getTenantId());
				dtoTemp.setStartFormKey(pd.hasStartFormKey());
				dtoTemp.setGraphicalNotation(pd.hasGraphicalNotation());
				dtoTemp.setSuspended(pd.isSuspended());

				dtoLists.add(dtoTemp);
			}
		}

		Page<DefinitionDto> processDefinitionPage = new PageImpl<DefinitionDto>(dtoLists, pageable.getPageable(),
				dtoLists != null ? dtoLists.size() : 0);

		return processDefinitionPage;
	}

	@RequestMapping(value = "/deploy", method = RequestMethod.POST, consumes = { "multipart/form-data" })
	@PreAuthorize("hasAnyAuthority('ADMIN','HIGH_MANAGER')")
	public @ResponseBody ExtjsAjaxResult deploy(@RequestParam(value = "file", required = true) MultipartFile file) {
		String fileName = file.getOriginalFilename();
		try {
			InputStream fileInputStream = file.getInputStream();
			String extension = FilenameUtils.getExtension(fileName);
			DeploymentBuilder deployment = repositoryService.createDeployment();
			if (extension.equals("zip") || extension.equals("bar")) {
				ZipInputStream zip = new ZipInputStream(fileInputStream);
				deployment.addZipInputStream(zip);
			} else {
				deployment.addInputStream(fileName, fileInputStream);
			}
			deployment.deploy();
			return new ExtjsAjaxResult(true, "部署成功!");
		} catch (Exception e) {
			e.printStackTrace();
			return new ExtjsAjaxResult(false, "部署失败!");
		}
	}

	@RequestMapping(value = "/resource")
	public void readResource(@RequestParam("pdid") String processDefinitionId,
			@RequestParam("resourceName") String resourceName, HttpServletResponse response) throws Exception {
		ProcessDefinitionQuery pdq = repositoryService.createProcessDefinitionQuery();
		ProcessDefinition pd = pdq.processDefinitionId(processDefinitionId).singleResult();

		InputStream resourceAsStream = repositoryService.getResourceAsStream(pd.getDeploymentId(), resourceName);

		byte[] b = new byte[1024];
		int len = -1;
		while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
			response.getOutputStream().write(b, 0, len);
		}
	}

	@RequestMapping(value = "/delete")
	@PreAuthorize("hasAnyAuthority('ADMIN','HIGH_MANAGER')")
	public @ResponseBody ExtjsAjaxResult deleteProcessDefinition(@RequestParam("deploymentId") String deploymentId) {
		try {
			repositoryService.deleteDeployment(deploymentId, true);
		} catch (Exception e) {
			e.printStackTrace();
			return new ExtjsAjaxResult(true, "删除失败!");
		}
		return new ExtjsAjaxResult(false, "删除成功!");
	}

	@RequestMapping(value = "/update/{state}/{processDefinitionId}")
	@PreAuthorize("hasAnyAuthority('ADMIN','HIGH_MANAGER')")
	public @ResponseBody ExtjsAjaxResult updateState(@PathVariable("state") String state,
			@PathVariable("processDefinitionId") String processDefinitionId) {
		try {
			if (state.equals("active")) {
				repositoryService.activateProcessDefinitionById(processDefinitionId, true, null);
			} else if (state.equals("suspend")) {
				repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null);
			}
			return new ExtjsAjaxResult(true,
					"已" + (state.equals("active") ? "激活" : "挂起") + "ID为[" + processDefinitionId + "]的流程定义。");
		} catch (Exception e) {
			e.printStackTrace();
			return new ExtjsAjaxResult(false, "操作失败!");
		}
	}

	@RequestMapping(value = "/convert-to-model/{processDefinitionId}")
	@PreAuthorize("hasAnyAuthority('ADMIN','HIGH_MANAGER')")
	public @ResponseBody ExtjsAjaxResult convertToModel(
			@PathVariable("processDefinitionId") String processDefinitionId) {
		try {
			ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
					.processDefinitionId(processDefinitionId).singleResult();
			InputStream bpmnStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),
					processDefinition.getResourceName());
			XMLInputFactory xif = XMLInputFactory.newInstance();
			InputStreamReader in = new InputStreamReader(bpmnStream, "UTF-8");
			XMLStreamReader xtr = xif.createXMLStreamReader(in);
			BpmnModel bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xtr);
			BpmnJsonConverter converter = new BpmnJsonConverter();
			com.fasterxml.jackson.databind.node.ObjectNode modelNode = converter.convertToJson(bpmnModel);
			Model modelData = repositoryService.newModel();
			modelData.setKey(processDefinition.getKey());
			modelData.setName(processDefinition.getResourceName());
			modelData.setCategory(processDefinition.getDeploymentId());

			ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
			modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, processDefinition.getName());
			modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
			modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, processDefinition.getDescription());
			modelData.setMetaInfo(modelObjectNode.toString());

			repositoryService.saveModel(modelData);
			repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8"));

			return new ExtjsAjaxResult(true, "转换成功！");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			return new ExtjsAjaxResult(false, "转换失败，转码错误！");
		} catch (XMLStreamException e) {
			e.printStackTrace();
			return new ExtjsAjaxResult(false, "转换失败，创建XML读取流错误！");
		}
	}
}
